package com.nmgolden.lanxin.api;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.nmgolden.lanxin.LanxinAppConfig;
import com.nmgolden.lanxin.LanxinHttpClient;
import com.nmgolden.lanxin.LanxinTokenManager;
import com.nmgolden.lanxin.model.*;

import java.util.*;

/**
 * 通讯录相关接口
 *
 * @author siger
 * @created 2024/5/18
 * @updated 2024/5/18
 */
public class AddressBookApi extends AbsApi {
    public AddressBookApi(LanxinAppConfig config, LanxinHttpClient lanxinHttpClient, LanxinTokenManager lanxinTokenManager) {
        super(config, lanxinHttpClient, lanxinTokenManager);
    }

    /**
     * 创建人员
     * <p>
     * 接口说明： 通过此接口，可以创建人员。仅组织内应用经过授权可以调用该接口。目前已支持批量创建人员，如需大量集中进行人员同步时，建议使用批量接口。特别说明：目前不支持应用并发调用人员创建接口，否则会出现添加人员到部门的操作失败，应用需保证串行化调用该接口。
     * 详情 <a href="https://developer.lanxin.cn/official/article?id=646eca933d4e4adb7039c0e1&module=back-end-api&article_id=646ed4923d4e4adb7039c11a">...</a>
     *
     * @return staffId
     */
    public String createUser(CreateUserRequestBody requestBody) {
        String urlTpl = "%s/v1/staffs/create?app_token=%s";
        String url = String.format(urlTpl, mLanxinAppConfig.getApiGateway(), mLanxinTokenManager.getAppToken());
        JSONObject jsonObject = mLanxinLanxinHttpClient.post(url, requestBody);

        return jsonObject.getString("staffId");
    }

    /**
     * 创建人员-批量
     * <p>
     * 接口说明： 通过此接口，可以批量创建人员，仅企业内应用经过授权可以调用该接口。特别说明：目前不支持应用并发调用人员创建接口，否则会出现添加人员到部门的操作失败，应用需要保证串行化调用该接口。单次创建人数上限为32。
     * <a href="https://developer.lanxin.cn/official/article?id=646eca933d4e4adb7039c0e1&module=back-end-api&article_id=646ed4a53d4e4adb7039c11b">...</a>
     *
     * @return 实例
     * [
     * {
     * "errCode": 10000,
     * "errMsg": "内部错误",
     * "staffid": ""
     * },{
     * "errCode": 0,
     * "errMsg": "ok",
     * "staffid": "8182980-111111xxjkdkdd"
     * }
     * ]
     */
    public JSONArray createUsers(List<CreateUserRequestBody> users) {
        String urlTpl = "%s/v1/staffs/batch/create?app_token=%s";
        String url = String.format(urlTpl, mLanxinAppConfig.getApiGateway(), mLanxinTokenManager.getAppToken());
        Map<String, List<CreateUserRequestBody>> requestBody = Collections.singletonMap("users", users);
        JSONObject jsonObject = mLanxinLanxinHttpClient.post(url, requestBody);

        return jsonObject.getJSONArray("list");
    }

    /**
     * 获取人员基本信息
     * <a href="https://developer.lanxin.cn/official/article?id=646eca933d4e4adb7039c0e1&module=back-end-api&article_id=646ed4b23d4e4adb7039c11c">...</a>
     *
     * @param staffId 用户（人员） id
     */
    public User getUser(String staffId) {
        if (staffId == null || staffId.isEmpty()) {
            return null;
        }

        String USER_BASIC_INFO_URL_TEMPLATE = "%s/v1/staffs/%s/fetch?app_token=%s&user_token=";
        String url = String.format(USER_BASIC_INFO_URL_TEMPLATE, mLanxinAppConfig.getApiGateway(), staffId, mLanxinTokenManager.getAppToken());
        JSONObject jsonObject = mLanxinLanxinHttpClient.get(url);
        User user = jsonObject.toJavaObject(User.class);
        user.setId(staffId);

        return user;
    }

    /**
     * 获取用户详细信息
     * <a href="https://developer.lanxin.cn/official/article?id=646eca933d4e4adb7039c0e1&module=back-end-api&article_id=646ed4c23d4e4adb7039c11d">...</a>
     *
     * @param staffId 用户（人员）id
     */
    public UserDetail getUserDetail(String staffId) {
        String USER_DETAIL_INFO_URL_TEMPLATE = "%s/v1/staffs/%s/infor/fetch?app_token=%s";
        String url = String.format(USER_DETAIL_INFO_URL_TEMPLATE, mLanxinAppConfig.getApiGateway(), staffId, mLanxinTokenManager.getAppToken());
        JSONObject jsonObject = mLanxinLanxinHttpClient.get(url);
        UserDetail userDetail = jsonObject.toJavaObject(UserDetail.class);

        userDetail.setStaffId(staffId);

        // 处理手机号
        JSONObject jo = jsonObject.getJSONObject("mobilePhone");
        if (jo != null) {
            userDetail.setMobile(jo.getString("number"));
        }

        return userDetail;
    }

    /**
     * 更新用户信息
     * <a href="https://developer.lanxin.cn/official/article?id=646eca933d4e4adb7039c0e1&module=back-end-api&article_id=646ed4cf3d4e4adb7039c11e">...</a>
     */
    public void updateUser(String staffId, UpdateUserRequestBody requestBody) {
        String UPDATE_USER_URL_TEMPLATE = "%s/v1/staffs/%s/update?app_token=%s";
        String url = String.format(UPDATE_USER_URL_TEMPLATE, mLanxinAppConfig.getApiGateway(), staffId, mLanxinTokenManager.getAppToken());
        mLanxinLanxinHttpClient.post(url, requestBody);
    }

    /**
     * 更新人员-批量
     * <p>
     * 接口说明： 通过此接口，可以批量更新人员信息，单次更新人数上限为32个，仅企业内应用经过授权可以调用该接口。特别说明：如果涉及人员的部门信息的更新，目前不支持应用并发调用该接口，否则会出现更新人员部门的操作失败，应用需保证串行化调用该接口。
     * <a href="https://developer.lanxin.cn/official/article?id=646eca933d4e4adb7039c0e1&module=back-end-api&article_id=646ed4df3d4e4adb7039c11f">...</a>
     *
     * @param users
     * @return [
     * {
     * "errCode":0,
     * "errMsg":"ok"
     * },
     * {
     * "errCode":500,
     * "errMsg":"更新失败"
     * }
     * ]
     */
    public JSONArray updateUsers(List<UpdateUserRequestBody> users) {
        String urlTpl = "%s/v1/staffs/batch/update?app_token=%s";
        String url = String.format(urlTpl, mLanxinAppConfig.getApiGateway(), mLanxinTokenManager.getAppToken());
        Map<String, List<UpdateUserRequestBody>> users1 = Collections.singletonMap("users", users);
        JSONObject responseData = mLanxinLanxinHttpClient.post(url, users1);

        return responseData.getJSONArray("infos");
    }

    /**
     * 删除人员
     * 删除人员，仅组织内应用经过授权可以调用该接口。特别说明：目前不支持应用并发调用该接口，否则会出现从部门中删除人员时操作失败，应用需保证串行化调用该接口。
     * <a href="https://developer.lanxin.cn/official/article?id=646eca933d4e4adb7039c0e1&module=back-end-api&article_id=646ed4f13d4e4adb7039c120">...</a>
     *
     * @param staffId 人员 id
     */
    public void deleteUser(String staffId) {
        String urlTpl = "%s/v1/staffs/%s/delete?app_token=%s";
        String url = String.format(urlTpl, mLanxinAppConfig.getApiGateway(), staffId, mLanxinTokenManager.getAppToken());
        mLanxinLanxinHttpClient.post(url, null);
    }


    /**
     * 搜索人员
     * 支持按分支限定搜索范围，在指定的分支范围内搜索人员。
     * <a href="https://developer.lanxin.cn/official/article?id=646eca933d4e4adb7039c0e1&module=back-end-api&article_id=646ed5083d4e4adb7039c121">...</a>
     */
    public SearchResult searchUser(Integer pageNum, Integer pageSize, String staffId, SearchRequestBody requestBody) {
        String urlTpl = "%s/v2/staffs/search?app_token=%s&user_id=%s&page=%s&page_size=%s";
        String url = String.format(urlTpl, mLanxinAppConfig.getApiGateway(), mLanxinTokenManager.getAppToken(), staffId, pageNum, pageSize);
        JSONObject resultJson = mLanxinLanxinHttpClient.post(url, requestBody);
        return resultJson.toJavaObject(SearchResult.class);
    }

    /**
     * 获取人员分支祖先列表
     * <p>
     * 获取某个人员所在的所有分支的祖先列表。
     * <a href="https://developer.lanxin.cn/official/article?id=646eca933d4e4adb7039c0e1&module=back-end-api&article_id=646ed5173d4e4adb7039c122">...</a>
     */
    public List<List<Department>> getDepartmentAncestors4User(String staffId) {

        String DEPARTMENT_ANCESTORS_URL_TEMPLATE = "%s/v1/staffs/%s/departmentancestors/fetch?app_token=%s&user_token=";
        String url = String.format(DEPARTMENT_ANCESTORS_URL_TEMPLATE, mLanxinAppConfig.getApiGateway(), staffId, mLanxinTokenManager.getAppToken());
        JSONArray ancestorDepartmentsForUser = mLanxinLanxinHttpClient.getArray(url);

        List<List<Department>> result = new ArrayList<>();
        for (int i = -1; ++i < ancestorDepartmentsForUser.size(); ) {
            JSONObject item = ancestorDepartmentsForUser.getJSONObject(i);
            List<Department> ancestorDepartments = item.getJSONArray("ancestorDepartments").toJavaList(Department.class);
            result.add(ancestorDepartments);
        }
        return result;
    }


    /**
     * 通过唯一标识获取人员ID
     * <a href="https://developer.lanxin.cn/official/article?id=646eca933d4e4adb7039c0e1&module=back-end-api&article_id=646ed6c83d4e4adb7039c124">...</a>
     *
     * @param idType  id 类型
     * @param idValue id 值
     */
    public String getStaffId(String idType, String idValue) {
        String ID_MAPPING_TEMPLATE = "%s/v2/staffs/id_mapping/fetch?app_token=%s&org_id=%s&id_type=%s&id_value=%s";
        String url = String.format(ID_MAPPING_TEMPLATE, mLanxinAppConfig.getApiGateway(), mLanxinTokenManager.getAppToken(), mLanxinAppConfig.getOrgId(), idType, idValue);
        JSONObject jsonObject = mLanxinLanxinHttpClient.get(url);

        return jsonObject.getString("staffId");
    }

    /**
     * 通过标签获取人员的ID列表
     * <p>
     * 在组织内，支持通过指定标签过滤规则来筛选目标人员。 EMC管理后台和开放平台接口都提供关于标签的创建、修改、删除及给人员添加标签等功能，开发人员可以调用开放平台接口获取已创建的所有标签分组，然后根据指定的分组ID再获取到该分组下的所有标签。
     * 具体请参见接口：获取标签分组列表、 获取标签分组详情
     * <a href="https://developer.lanxin.cn/official/article?id=646eca933d4e4adb7039c0e1&module=back-end-api&article_id=646ed6d73d4e4adb7039c125">...</a>
     *
     * @return staffIds
     */
    public GetStaffIdsByTagsResult getStaffIdsByTags(Integer pageNum, Integer pageSize, List<String> tags) {
        String urlTpl = "%s/v1/tags/staffs/fetch?app_token=%s&page=%s&page_size=%s";
        String url = String.format(urlTpl, mLanxinAppConfig.getApiGateway(), mLanxinTokenManager.getAppToken(), pageNum, pageSize);
        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("orgId", mLanxinAppConfig.getAppId());
        requestBody.put("tagFilters", tags);
        JSONObject jsonObject = mLanxinLanxinHttpClient.post(url, requestBody);

        return jsonObject.toJavaObject(GetStaffIdsByTagsResult.class);
    }


    /**
     * 获取通讯录扩展字段ID列表
     * 获取组织内通讯录的扩展字段ID列表。
     * <a href="https://developer.lanxin.cn/official/article?id=646eca933d4e4adb7039c0e1&module=back-end-api&article_id=646ed6e73d4e4adb7039c126">...</a>
     */
    public List<ExtraField> getExtraFields() {

        String GET_EXTRA_FIELD_IDS_TEMPLATE = "%s/v1/org/%s/extrafieldids/fetch?app_token=%s&page=1&page_size=10000";
        String url = String.format(GET_EXTRA_FIELD_IDS_TEMPLATE, mLanxinAppConfig.getApiGateway(), mLanxinAppConfig.getOrgId(), mLanxinTokenManager.getAppToken());
        JSONObject responseData = mLanxinLanxinHttpClient.get(url);

        String extraFieldIds = responseData.getString("extraFieldIds");
        if (null == extraFieldIds) {
            return Collections.emptyList();
        }
        return JSON.parseArray(extraFieldIds, ExtraField.class);
    }


    /**
     * 创建分支
     * 创建分支。接口需要拥有对应的授权，仅组织内应用经过授权可以调用该接口。
     * <a href="https://developer.lanxin.cn/official/article?id=646eca933d4e4adb7039c0e1&module=back-end-api&article_id=646ed6fe3d4e4adb7039c127">...</a>
     */
    public String createDepartment(CreateDepartmentRequestBody requestBody) {
        String urlTpl = "%s/v1/departments/create?app_token=%s";
        String url = String.format(urlTpl, mLanxinAppConfig.getApiGateway(), mLanxinTokenManager.getAppToken());
        JSONObject responseData = mLanxinLanxinHttpClient.post(url, requestBody);

        return responseData.getJSONObject("department").getString("id");
    }

    /**
     * 获取部门详情
     * <a href="https://developer.lanxin.cn/official/article?id=646eca933d4e4adb7039c0e1&module=back-end-api&article_id=646ed70e3d4e4adb7039c128">...</a>
     *
     * @param departmentId 部门 id
     */
    public Department getDepartment(String departmentId) {
        String DEPARTMENT_URL_TEMPLATE = "%s/v1/departments/%s/fetch?app_token=%s";
        String url = String.format(DEPARTMENT_URL_TEMPLATE, mLanxinAppConfig.getApiGateway(), departmentId, mLanxinTokenManager.getAppToken());
        JSONObject data = mLanxinLanxinHttpClient.get(url);
        return data.toJavaObject(Department.class);
    }

    /**
     * 更新分支
     * <a href="https://developer.lanxin.cn/official/article?id=646eca933d4e4adb7039c0e1&module=back-end-api&article_id=646ed71b3d4e4adb7039c129">...</a>
     */
    public void updateDepartment(String deptId, UpdateDepartmentRequestBody requestBody) {
        String DEPARTMENT_URL_TEMPLATE = "%s/v1/departments/%s/update?app_token=%s";
        String url = String.format(DEPARTMENT_URL_TEMPLATE, mLanxinAppConfig.getApiGateway(), deptId, mLanxinTokenManager.getAppToken());
        mLanxinLanxinHttpClient.post(url, requestBody);
    }

    /**
     * 删除分支
     * 删除分支。仅组织内应用经过授权可以调用该接口。
     */
    public void deleteDepartment(String deptId) {
        String urlTpl = "%s/v1/departments/%s/delete?app_token=%s";
        String url = String.format(urlTpl, mLanxinAppConfig.getApiGateway(), deptId, mLanxinTokenManager.getAppToken());
        mLanxinLanxinHttpClient.post(url);
    }

    /**
     * 获取子部门（分支）
     *
     * @param departmentId 部门 id
     */
    public List<Department> getSubDepartments(String departmentId) {
        String DEPARTMENTS_URL_TEMPLATE = "%s/v1/departments/%s/children/fetch?app_token=%s&user_token=%s";
        String url = String.format(DEPARTMENTS_URL_TEMPLATE, mLanxinAppConfig.getApiGateway(), departmentId, mLanxinTokenManager.getAppToken(), "");
        JSONObject response = mLanxinLanxinHttpClient.get(url);
        if (!response.containsKey("departments")) {
            return null;
        }
        return response.getJSONArray("departments").toJavaList(Department.class);
    }

    /**
     * 获取部门（分支）下的用户
     *
     * @param departmentId 部门（分支）id
     */
    public JSONObject getUsersInDepartment(Integer pageNum, Integer pageSize, String departmentId) {

        String USERS_URL_TEMPLATE = "%s/v1/departments/%s/staffs/fetch?app_token=%s&user_token=%s&page=%d&page_size=%d";
        String url = String.format(USERS_URL_TEMPLATE, mLanxinAppConfig.getApiGateway(), departmentId, mLanxinTokenManager.getAppToken(), "", pageNum, pageSize);

        return mLanxinLanxinHttpClient.get(url);

    }

    /**
     * 添加分支成员
     * <a href="https://developer.lanxin.cn/official/article?id=646eca933d4e4adb7039c0e1&module=back-end-api&article_id=646ed7573d4e4adb7039c12d">...</a>
     */
    public void addMember(String deptId, String staffId) {
        String urlTpl = "%s/v1/departments/%s/staffs/%s/create?app_token=%s";
        String url = String.format(urlTpl, mLanxinAppConfig.getApiGateway(), deptId, staffId);
        mLanxinLanxinHttpClient.post(url);
    }

    /**
     * 删除分支成员
     * <a href="https://developer.lanxin.cn/official/article?id=646eca933d4e4adb7039c0e1&module=back-end-api&article_id=646ed7673d4e4adb7039c12e">...</a>
     */
    public void removeMember(String deptId, String staffId) {
        String urlTpl = "%s/v1/departments/%s/staffs/%s/delete?app_token=%s";
        String url = String.format(urlTpl, mLanxinAppConfig.getApiGateway(), deptId, staffId);
        mLanxinLanxinHttpClient.post(url);
    }


    /**
     * 移动分支
     * <a href="https://developer.lanxin.cn/official/article?id=646eca933d4e4adb7039c0e1&module=back-end-api&article_id=646ed7803d4e4adb7039c12f">...</a>
     */
    public void moveDepartment(String departmentId, String newParentId) {
        String urlTpl = "%s/v1/departments/parent/update?app_token=%s";
        Map<String, String> requestBody = new HashMap<>();
        requestBody.put("departmentId", departmentId);
        requestBody.put("newParentId", newParentId);
        String url = String.format(urlTpl, mLanxinAppConfig.getApiGateway());
        mLanxinLanxinHttpClient.post(url, requestBody);
    }


    /**
     * 带有某标签的用户
     * {
     * "orgId": "524288",
     * "tagFilters": [
     * {
     * "tags": [
     * "524288-xxxxxxxx",
     * ]
     * }
     * ]
     * }
     */
    public List<String> getUserIdsInTag(String tagId) {

        String USER_ID_IN_TAG_URL_TEMPLATE = "%s/v1/tags/staffids/fetch?app_token=%s&user_token=";
        String url = String.format(USER_ID_IN_TAG_URL_TEMPLATE, mLanxinAppConfig.getApiGateway(), mLanxinTokenManager.getAppToken());
        String requestJson = "{\"orgId\":\"" + mLanxinAppConfig.getOrgId() + "\",\"tagFilters\":[{\"tags\":[\"" + tagId + "\"]}]}";
        Map<String, Object> requestBody = JSON.parseObject(requestJson, new TypeReference<Map<String, Object>>() {
        });
        JSONObject jsonObject = mLanxinLanxinHttpClient.post(url, requestBody);
        List<String> idList = new ArrayList<>();

        if (jsonObject.containsKey("staffs")) {
            JSONArray staffs = jsonObject.getJSONArray("staffs");

            for (Object staff : staffs) {
                JSONObject jo = (JSONObject) staff;
                idList.add(jo.getString("id"));
            }
        }

        return idList;
    }

    /**
     * 标签组列表
     */
    public List<TagGroup> getTagGroups() {

        String GET_TAG_LIST_TEMPLATE = "%s/v1/taggroups/fetch?app_token=%s&user_token=%s";
        String url = String.format(GET_TAG_LIST_TEMPLATE, mLanxinAppConfig.getApiGateway(), mLanxinTokenManager.getAppToken(), "");
        Map<String, Object> body = new HashMap<>();
        body.put("orgId", mLanxinAppConfig.getOrgId());
        body.put("categoryList", Collections.singletonList(1));
        JSONObject data = mLanxinLanxinHttpClient.post(url, body);
        JSONArray tagGroupIds = data.getJSONArray("tagGroupIds");

        List<TagGroup> groupList = new ArrayList<>();
        for (int i = -1; ++i < tagGroupIds.size(); ) {
            String tagId = tagGroupIds.getString(i);
            JSONObject info = getTagGroupInfo(tagId);
            TagGroup group = info.toJavaObject(TagGroup.class);
            groupList.add(group);
        }

        return groupList;
    }

    /**
     * 获取标签分组详情
     *
     * @param tagId 标签 id
     */
    public JSONObject getTagGroupInfo(String tagId) {
        String TAG_INFO_TEMPLATE = "%s/v1/taggroups/%s/fetch?app_token=%s&user_token=%s";
        String infoUrl = String.format(TAG_INFO_TEMPLATE, mLanxinAppConfig.getApiGateway(), tagId, mLanxinTokenManager.getAppToken(), "");
        return mLanxinLanxinHttpClient.get(infoUrl);
    }

}
